#include "fxcc/core/graph/common/MaterialData.h"
#include "fxcc/yml/Serializer.h"

using namespace fxcc::graph::common;

MaterialData::MaterialData(aiMaterial *mat, const std::string &dir)
    : m_Dir(dir)
{
    Load(mat->GetName(), m_Name);
    
    LoadTextures(mat, aiTextureType_NONE, "NONE");
    LoadTextures(mat, aiTextureType_DIFFUSE, "DIFFUSE");
    LoadTextures(mat, aiTextureType_SPECULAR, "SPECULAR");
    LoadTextures(mat, aiTextureType_AMBIENT, "AMBIENT");
    LoadTextures(mat, aiTextureType_EMISSIVE, "EMISSIVE");
    LoadTextures(mat, aiTextureType_HEIGHT, "HEIGHT");
    LoadTextures(mat, aiTextureType_NORMALS, "NORMALS");
    LoadTextures(mat, aiTextureType_SHININESS, "SHININESS");
    LoadTextures(mat, aiTextureType_OPACITY, "OPACITY");
    LoadTextures(mat, aiTextureType_DISPLACEMENT, "DISPLACEMENT");
    LoadTextures(mat, aiTextureType_LIGHTMAP, "LIGHTMAP");
    LoadTextures(mat, aiTextureType_REFLECTION, "REFLECTION");
    LoadTextures(mat, aiTextureType_BASE_COLOR, "BASE_COLOR");
    LoadTextures(mat, aiTextureType_NORMAL_CAMERA, "NORMAL_CAMERA");
    LoadTextures(mat, aiTextureType_EMISSION_COLOR, "EMISSION_COLOR");
    LoadTextures(mat, aiTextureType_METALNESS, "METALNESS");
    LoadTextures(mat, aiTextureType_DIFFUSE_ROUGHNESS, "DIFFUSE_ROUGHNESS");
    LoadTextures(mat, aiTextureType_AMBIENT_OCCLUSION, "AMBIENT_OCCLUSION");
    LoadTextures(mat, aiTextureType_UNKNOWN, "UNKNOWN");

    std::vector<std::shared_ptr<Property>> m_Properties;

    for (unsigned int i = 0; i < mat->mNumProperties; i++)
    {
        auto p = mat->mProperties[i];

        int dataLen = p->mDataLength;
        char* data = p->mData;
        int index = p->mIndex;
        std::string key = p->mKey.C_Str();

        switch (p->mType)
        {
        case aiPTI_Float:
            m_Params.AddFloat(key, data, dataLen);
            break;
        case aiPTI_Double:
            m_Params.AddDouble(key, data, dataLen);
            break;
        case aiPTI_Integer:
            m_Params.AddInt(key, data, dataLen);
            break;
        case aiPTI_Buffer:
            break;
        case aiPTI_String:
            AddString(key, data, dataLen);
            break;
        default:
            break;
        }
    }
};




void fxcc::graph::common::MaterialData::AddString(const std::string& key, char* data, int dataLen)
{
    if (dataLen < 4 || data == nullptr) return;
    uint32_t strLen = *(uint32_t*)data;
    if (strLen == 0 || strLen > static_cast<uint32_t>(dataLen - 4)) return;
    const char* strData = data + 4;
    std::string value(strData, strLen );
    m_Strings[key] = value;
}

void MaterialData::LoadTextures(aiMaterial *mat, aiTextureType type, const std::string &info)
{
    unsigned int num = mat->GetTextureCount(type);

    for (int i = 0; i < num; i++)
    {
        aiString str;
        mat->GetTexture(type, i, &str);

        std::string fileName;
        Load(str, fileName);

        fs::path _texturePath = fs::path(m_Dir) / fs::path(fileName);
        std::string texturePath = _texturePath.string();
        texturePath = normalizePath(texturePath);
        m_Textures[info].m_Textures.push_back(texturePath);
    }
}
